/*
 * ﻿Copyright (C) 2009-2013 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.newmainsoftech.gwetons.client.style.css;

import java.util.logging.Level;

import com.newmainsoftech.gwetons.client.JavaScriptObjectUtil;
import com.newmainsoftech.gwetons.client.style.css.StyleChangerState.State;
import com.newmainsoftech.gwetons.shared.logging.LoggerWrap;
import com.newmainsoftech.gwetons.shared.logging.LoggerWrapAdapterTemplate;
import com.newmainsoftech.gwetons.shared.timer.TimerEventListener;

/**
 * This instance will be instantiated for each element of cscbsDataSet.styleChangerDataArray property.
 * 
 * @author <a href="mailto:artymt@gmail.com">Arata Y.</a>
 */
public class StyleChangerTimerEvent extends LoggerWrapAdapterTemplate implements TimerEventListener {
	@Override
	protected String getNameForLogging() {
		return this.getClass().getName();
	}
	
	final DataUnitByStyleSelector dataUnitByStyleSelector;		
	final StyleChangerTimerEventManager styleChangerTimerEventManager;
	
	public StyleChangerTimerEvent( 
			DataUnitByStyleSelector dataUnitByStyleSelector, 
			StyleChangerTimerEventManager styleChangerTimerEventManager) 
	{
		this.dataUnitByStyleSelector = dataUnitByStyleSelector;
		this.styleChangerTimerEventManager = styleChangerTimerEventManager;
	}
	
	boolean finished = true;
		public boolean isFinished() {
			return finished;
		}
		void setFinished( boolean finished) {
			this.finished = finished;
		}

	void completeTimerEvent( boolean abnormalTermination) {
		setFinished( true);
		StyleChangerTimerEventManager.getTimerController().cancel( this);
		styleChangerTimerEventManager.startNextStyleChangerTimerEvent( this, abnormalTermination);
	}
	
	public void fire() {
		String methodName = "fire";
		LoggerWrap logUtil = getLoggerWrap();
		logUtil.entering( methodName, null);
		
		String styleValueStr = "";
		Boolean isEndReached = Boolean.TRUE;
		String endValueStr = dataUnitByStyleSelector.getEndValueStr();
		if ( endValueStr != null) {
			if ( "".equals( endValueStr)) {
				styleValueStr = "";	// style setting will be eliminated.
			}
			else {
				isEndReached = Boolean.FALSE;
				
				if ( 
						dataUnitByStyleSelector.isInitValueNumeric() 
						&& dataUnitByStyleSelector.isEndValueNumeric()
						) 
				{
					
						int period = dataUnitByStyleSelector.getPeriod().intValue();
						int interval = dataUnitByStyleSelector.getInterval().intValue();
						StyleChangerState styleChangerState = dataUnitByStyleSelector.styleChangerState;
						if ( period < interval) {
							// Use endValue for style
							if ( dataUnitByStyleSelector.isNumericColor()) {
								styleValueStr 
								= "#" + DataUnitByStyleSelector.getRGBColorHexStr( 
											styleChangerState.getStateValue( State.EndValue).intValue() 
											);
							}
							else {
								styleValueStr 
								= styleValueStr + dataUnitByStyleSelector.getValuePrefix()
									+ styleChangerState.getStateValue( State.EndValue).toString() 
									+ dataUnitByStyleSelector.getValueUnit() 
									+ dataUnitByStyleSelector.getValueSuffix();
								styleValueStr 
								= JavaScriptObjectUtil.getURIComponentDecoded( styleValueStr);
							}
							
							isEndReached = Boolean.TRUE;
						}
						else { // period >= interval
							// Calculate style by adding diffUnit to currentValue
							int stateIntValue 
							= styleChangerState.getStateValue( State.CurrentValue).intValue() 
								+ styleChangerState.getStateValue( State.DiffUnit).intValue();
							styleChangerState.setStateValue( State.CurrentValue, stateIntValue);
								isEndReached = styleChangerState.isEndReached();
								if ( isEndReached == null) {
									logUtil.log(
											Level.WARNING,
											"Failed to know whether current value reached end value."
											);
									completeTimerEvent( true);
									
									logUtil.exiting( methodName);
									return;
								}
								if ( isEndReached.booleanValue()) {
									styleChangerState.setStateValue( 
											State.CurrentValue, 
											styleChangerState.getStateValue( State.EndValue).intValue()
											);
								}
							
							if ( dataUnitByStyleSelector.isNumericColor()) {
								stateIntValue 
								= styleChangerState.getStateValue( State.CurrentBlue).intValue() 
									+ styleChangerState.getStateValue( State.BlueDiffUnit).intValue();
								styleChangerState.setStateValue( State.CurrentBlue, stateIntValue);
									if ( isEndReached.booleanValue()) {
										styleChangerState.setStateValue( 
												State.CurrentBlue, 
												styleChangerState.getStateValue( State.EndBlue).intValue()
												);
									}
									
								stateIntValue 
								= styleChangerState.getStateValue( State.CurrentGreen).intValue() 
									+ styleChangerState.getStateValue( State.GreenDiffUnit).intValue();
								styleChangerState.setStateValue( State.CurrentGreen, stateIntValue);
									if ( isEndReached.booleanValue()) {
										styleChangerState.setStateValue( 
												State.CurrentGreen, 
												styleChangerState.getStateValue( State.EndGreen).intValue()
												);
									}
									
								stateIntValue 
								= styleChangerState.getStateValue( State.CurrentRed).intValue() 
									+ styleChangerState.getStateValue( State.RedDiffUnit).intValue();
								styleChangerState.setStateValue( State.CurrentRed, stateIntValue);
									if ( isEndReached.booleanValue()) {
										styleChangerState.setStateValue( 
												State.CurrentRed, 
												styleChangerState.getStateValue( State.EndRed).intValue()
												);
									}
								
								String colorStr 
								= DataUnitByStyleSelector.get2ByteHexStringValue(
										styleChangerState.getStateValue( State.CurrentBlue).intValue()
										);
									colorStr 
									= DataUnitByStyleSelector.get2ByteHexStringValue(
											styleChangerState.getStateValue( State.CurrentGreen).intValue() 
											) 
										+ colorStr;
									colorStr 
									= DataUnitByStyleSelector.get2ByteHexStringValue(
											styleChangerState.getStateValue( State.CurrentRed).intValue()
											) 
										+ colorStr;
								
								styleValueStr = "#" + colorStr;
							}
							else { // Not for color
								styleValueStr 
								= styleValueStr + dataUnitByStyleSelector.getValuePrefix()
									+ styleChangerState.getStateValue( State.CurrentValue).toString() 
									+ dataUnitByStyleSelector.getValueUnit() 
									+ dataUnitByStyleSelector.getValueSuffix();
								styleValueStr 
								= JavaScriptObjectUtil.getURIComponentDecoded( styleValueStr);
							}
						}
				}
				else { 
				// either or both of initValue and endValue is not numeric
				// endValue is neither null nor empty string 
					styleValueStr = styleValueStr 
							+ dataUnitByStyleSelector.getValuePrefix() 
							+ dataUnitByStyleSelector.getEndValueStr();
					if ( dataUnitByStyleSelector.isEndValueNumeric()) {
						styleValueStr = styleValueStr 
								+ dataUnitByStyleSelector.getValueUnit(); 
					}
					styleValueStr = styleValueStr 
							+ dataUnitByStyleSelector.getValueSuffix();
					
					styleValueStr 
					= JavaScriptObjectUtil.getURIComponentDecoded( styleValueStr);
					
					isEndReached = Boolean.TRUE;
				}
			}
			
			dataUnitByStyleSelector.setStyleValueStr( styleValueStr);
			
			boolean addCssRuleToStylesheetResult 
			= DataUnitByStyleSelector.addCssRuleToStylesheet(
					dataUnitByStyleSelector.getSelector(), 
					dataUnitByStyleSelector.getStyle(), 
					styleValueStr 
					);
			if ( !addCssRuleToStylesheetResult) { 
			// When failed to update this style, remove this style to avoid later further processing 
				logUtil.log( 
						Level.WARNING, 
						"Flagged DataUnitByStyleSelector instance for " + dataUnitByStyleSelector.getStyle() 
						+ " style of " + dataUnitByStyleSelector.getSelector() + " selector for removal " 
						+ "because of failure of adding its style setting to style sheet(s)."
						);
				completeTimerEvent( true);
				
				logUtil.exiting( methodName);
				return;
			}
		}
		
		if ( isEndReached.booleanValue()) { 
			if ( dataUnitByStyleSelector.getReversible().booleanValue()) {
				if ( dataUnitByStyleSelector.isInReverse()) { // already in reverse state
					dataUnitByStyleSelector. styleChangerState.reverse();
					completeTimerEvent( false);
				}
				else {
					dataUnitByStyleSelector.styleChangerState.reverse();
				}
				logUtil.exiting( methodName);
				return;
			}
			else { // Not reversible
				// Reset initValue to current state
				StyleChangerState styleChangerState = dataUnitByStyleSelector.styleChangerState;
				
				if ( 
						!dataUnitByStyleSelector.isInitValueNumeric() 
						|| !dataUnitByStyleSelector.isEndValueNumeric() 
						|| !dataUnitByStyleSelector.isNumericColor()
						) 
				{
					styleValueStr = dataUnitByStyleSelector.getInitValueStr();
					if ( (styleValueStr != null) && !"".equals( styleValueStr)) {
						styleValueStr = styleValueStr 
								+ dataUnitByStyleSelector.getValuePrefix()
								+ dataUnitByStyleSelector.getInitValueStr();
						if ( dataUnitByStyleSelector.isInitValueNumeric()) {
							styleValueStr = styleValueStr 
									+ dataUnitByStyleSelector.getValueUnit(); 
						}
						styleValueStr = styleValueStr  
								+ dataUnitByStyleSelector.getValueSuffix();
						styleValueStr 
						= JavaScriptObjectUtil.getURIComponentDecoded( styleValueStr);
					}
				}
				else {
					styleValueStr 
					= "#" + DataUnitByStyleSelector.getRGBColorHexStr( 
								styleChangerState.getStateValue( State.InitValue).intValue() 
								);
					
					styleChangerState.setStateValue( 
							State.CurrentValue, 
							styleChangerState.getStateValue( State.InitValue));
					styleChangerState.setStateValue( 
							State.CurrentBlue,
							styleChangerState.getStateValue( State.InitBlue).intValue());
					styleChangerState.setStateValue( 
							State.CurrentGreen,
							styleChangerState.getStateValue( State.InitGreen).intValue());
					styleChangerState.setStateValue( 
							State.CurrentRed,
							styleChangerState.getStateValue( State.InitRed).intValue());
				}
				
				dataUnitByStyleSelector.setStyleValueStr( styleValueStr);
				
				completeTimerEvent( false);
			}
		}
		
		logUtil.exiting( methodName);
	}
}
